package main

import (
	"errors"
	"fmt"
)

/*
关于函数和方法
*/

//   名字  要传给的参数       函数的返回类型
//func name(parameter-list) (result-list) {
//	body
//}

// 这种写法就是接受一个参数 然后返回两个值
// 如果一个函数的所有返回值都在函数签名中显式命名了变量名
// 那么该函数的return语句可以省略操作数。这称之为bare return。
func add(a, b int) (sum int) {
	sum = a + b
	return // 省略了返回值，自动返回 sum
}

func divide(a, b int) (result int, err error) {
	if b == 0 {
		err = errors.New("division by zero")
		return // 裸返回，返回当前的 result 和 err
	}
	result = a / b
	return // 裸返回
}

/**
方法是与特定类型关联的函数。
它的定义类似于函数，但在函数名前面有一个接收者（receiver），表示该方法属于哪个类型。
通过方法，可以让某个类型的值调用该方法，实现面向对象的编程风格。

func (receiver Type) methodName(params) returnType {
    // 方法体
}

receiver：接收者变量名，类似于面向对象语言中的 this 或 self。
Type：接收者的类型，可以是结构体类型或自定义类型。
methodName：方法名。
params：参数列表。
returnType：返回值类型（可选）。
*/

// 定义一个结构体类型
type Rectangle struct {
	width, height float64
}

// 给 Rectangle 类型定义一个方法，计算面积
func (r Rectangle) Area() float64 {
	return r.width * r.height
}

//当调用一个函数时，会对其每一个参数值进行拷贝，如果一个函数需要更新一个变量，
//或者函数的其中一个参数实在太大我们希望能够避免进行这种默认的拷贝，这种情况下我们就需要用到指针

// 指针接收者，修改有效
func (r *Rectangle) IncrementPointer() float64 {
	r.height++
	r.width++
	return r.width * r.height
}

func main() {
	fmt.Println(add(1, 2))
	fmt.Println(divide(1, 0))

	// 个人感觉像是学习 java面向对象的实现，因为go不是面向对象的编程
	// 用结构体实现类的样式，方法实现类的方法 具体调用通过 结构体的变量 调用结构体的方法
	rect := Rectangle{width: 10, height: 5}
	fmt.Println("Area:", rect.Area()) // 调用方法

	/**
	函数和方法两者的不同点
	含义不同：函数function是⼀段具有独⽴功能的代码，可以被反复多次调⽤，从⽽实现代码复⽤。⽽⽅法method是⼀个类的⾏为功能，只有该类的对象才能调⽤。
	接收者：方法有接收者，函数没有接收者
	函数不可以重名，方法可以重名
	调用的方式不一样
	其实最关键的还是go对指针的支持。导致的在声明实现调用的时候不一样。
	*/

	re := Rectangle{width: 10, height: 5}
	fmt.Println(re) //{10 5}
	fmt.Println("Area:", re.IncrementPointer())
	fmt.Println(re) // {11 6}
}
